{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "98bbe059-f253-43b5-85cd-c8eb21311153",
   "metadata": {},
   "source": [
    "# Basic Ollama Usage Examples\n",
    "\n",
    "This shows the simplest ways to replace OpenAI/other API calls with Ollama.\n",
    "Perfect for understanding the core concepts before moving to agents.\n",
    "\n",
    "1) Direct API call\n",
    "2) Ollama API parameters\n",
    "3) Basic LangChain Integration\n",
    "4) Conversation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "26077269-865a-44ee-9c55-3a0614e36f32",
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import time"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e55c3f22-c272-4487-8c3b-58eff99231f5",
   "metadata": {},
   "source": [
    "# Lets check if Ollama is runninig:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "96c0e4d3-088a-45ef-8e6b-a86ca0dfd2db",
   "metadata": {},
   "outputs": [],
   "source": [
    "def check_ollama_running():\n",
    "    \"\"\"Check if Ollama is available.\"\"\"\n",
    "    try:\n",
    "        response = requests.get(\"http://localhost:11434/api/tags\", timeout=5)\n",
    "        return response.status_code == 200\n",
    "    except:\n",
    "        return False\n",
    "\n",
    "if not check_ollama_running():\n",
    "    print(\"❌ Ollama not running!\")\n",
    "    print(\"Start it with: ollama serve\")\n",
    "    print(\"And make sure you have a model: ollama pull llama3.1:8b\")\n",
    "else:\n",
    "    print(\"✅ Ollama is running\\n\")\n",
    "    print(\"🚀 Basic Ollama Usage Examples\")\n",
    "    print(\"=\" * 40)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8757427b-ab1b-42e5-8ab9-b91a17b92dce",
   "metadata": {},
   "source": [
    "# Direct API"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20553578-d6e6-4bfd-8296-9374748bcb82",
   "metadata": {},
   "source": [
    "# system vs user call:\n",
    "✅ role: \"system\"\n",
    "Purpose: Sets initial behavior, tone, or constraints for the model.\n",
    "Example Use: Define the assistant's personality, scope, or instructions before the conversation starts.\n",
    "The model reads it once and uses it to shape all following responses.\n",
    "Not shown to the user in most applications.\n",
    "\n",
    "✅ role: \"user\"\n",
    "Purpose: Represents the actual question or input from the user.\n",
    "Triggers the model to respond.\n",
    "Can be followed by assistant messages to continue the back-and-forth dialogue."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42b113ca-f385-45ce-87a4-7a289da45cdc",
   "metadata": {},
   "outputs": [],
   "source": [
    "def example_1_direct_api(sys_promt, usr_promt):\n",
    "    # This replaces OpenAI API calls\n",
    "    # response = requests.post(\"http://localhost:11434/api/chat\", json={\n",
    "    #     \"model\": \"llama3.1:8b\",\n",
    "    #     \"messages\": [\n",
    "    #         {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
    "    #         {\"role\": \"user\", \"content\": \"What is Python?\"}\n",
    "    #     ]\n",
    "    # })\n",
    "    response = requests.post(\"http://localhost:11434/api/chat\", json={\n",
    "        \"model\": \"llama3.1:8b\",\n",
    "        \"messages\": [{\"role\": \"system\", \"content\": sys_promt},\n",
    "                     {\"role\": \"user\", \"content\":  usr_promt}\n",
    "                     ],\n",
    "        \"stream\": False  # Ensure it's not streaming\n",
    "    })\n",
    "    if response.status_code == 200:\n",
    "        result = response.json()\n",
    "        print(f\"Response: {result[\"message\"][\"content\"]}\")\n",
    "    else:\n",
    "        print(f\"Error: {response.status_code}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "09f43c78-270a-483d-a427-2a94f56b4868",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Example 1: Direct API Call\")\n",
    "print(\"-\" * 30)\n",
    "sys_promt = \"You are a helpful assistant.\"\n",
    "usr_promt = \"What is Python?\"\n",
    "example_1_direct_api(sys_promt,usr_promt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6658f7f-c8a7-4126-aabb-e6a98aac9cce",
   "metadata": {},
   "source": [
    "## Ollama API Parameters\n",
    "\n",
    "Ollama provides extensive customization options. Here are the most commonly used parameters:\n",
    "\n",
    "| Parameter | Type | Default | Description |\n",
    "|-----------|------|---------|-------------|\n",
    "| `model` | string | - | **Required.** Model identifier (e.g., `\"llama3.1:8b\"`) |\n",
    "| `messages` | array | - | Chat conversation for `/api/chat` |\n",
    "| `stream` | boolean | true | Stream response as it's generated |\n",
    "| `temperature` | float | 0.8 | Randomness (0.0 = deterministic, 2.0 = very random) |\n",
    "| `top_p` | float | 0.9 | Nucleus sampling (0.1 = top 10% tokens only) |\n",
    "| `num_predict` | int | 128 | Maximum tokens to generate (-1 = unlimited) |\n",
    "| `repeat_penalty` | float | 1.1 | Penalty for repeating tokens |\n",
    "| `system` | string | - | System message to guide behavior |\n",
    "| `stop` | array | - | Stop generation at these strings |\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4d50bb6-034d-4655-a9fc-3e02e87f3b42",
   "metadata": {},
   "outputs": [],
   "source": [
    "def example_2_with_parameters(temperature, num_predict, usr_promt):\n",
    "   \n",
    "    response = requests.post(\"http://localhost:11434/api/chat\", json={\n",
    "        \"model\": \"llama3.1:8b\",\n",
    "        \"messages\": [{\"role\": \"user\", \"content\": usr_promt}],\n",
    "        \"temperature\": temperature,  # Higher temperature for creativity\n",
    "        \"num_predict\": num_predict,   # Limit response length\n",
    "        \"stream\": False  # Ensure it's not streaming\n",
    "    })\n",
    "    \n",
    "    if response.status_code == 200:\n",
    "        result = response.json()[\"message\"][\"content\"]\n",
    "        print(f\"Creative response: {result}\")\n",
    "    else:\n",
    "        print(f\"Error: {response.status_code}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aaeb0e36-2c2c-4792-8f9f-c3799a31d487",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"\\nExample 2: With Parameters\")\n",
    "print(\"-\" * 30)\n",
    "usr_promt = \"Write a creative story about a robot.\"\n",
    "temperature = 0.8\n",
    "num_predict = 100\n",
    "example_2_with_parameters(temperature, num_predict, usr_promt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25384d92-57f2-4486-9c21-93ac0befb814",
   "metadata": {},
   "source": [
    "# LangChain Integration\n",
    "\n",
    "| Feature | ChatOllama | Direct API |\n",
    "|---------|------------|------------|\n",
    "| `Abstraction level` | High | Low |\n",
    "| `Ease of use` | Easier | Manual formatting required |\n",
    "| `Customization (headers, etc.)` | Limited | Full |\n",
    "| `Dependency` | Requires LangChain | Only requests | \n",
    "| `Best for` | RAG pipelines, fast prototyping | Custom tools, low-level control |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2784ee49-5953-4872-bf1d-6c3cbbb6b521",
   "metadata": {},
   "outputs": [],
   "source": [
    "def example_3_langchain_basic(usr_promt):    \n",
    "    try:\n",
    "        from langchain_community.chat_models import ChatOllama\n",
    "        \n",
    "        # Replace ChatOpenAI with ChatOllama\n",
    "        llm = ChatOllama(model=\"llama3.1:8b\", temperature=0.1)\n",
    "        \n",
    "        response = llm.invoke(usr_promt)\n",
    "        print(f\"LangChain response: {response.content}\")\n",
    "        \n",
    "    except ImportError:\n",
    "        print(\"LangChain not installed. Run: pip install langchain langchain-community\")\n",
    "    except Exception as e:\n",
    "        print(f\"Error: {e}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b309023-124e-43c9-a7ab-86ca4fd001ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"\\nExample 3: LangChain Integration\")\n",
    "print(\"-\" * 30)\n",
    "usr_promt = \"Explain machine learning in one sentence.\"\n",
    "example_3_langchain_basic(usr_promt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1747720-a40b-4cf8-ad98-9addc8e9c339",
   "metadata": {},
   "source": [
    "# Maintaining Conversation Context"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2e50d5c-86f1-447f-b2f2-064ff7b1665b",
   "metadata": {},
   "source": [
    "In a conversation with a language model, messages are exchanged between different roles. The \"assistant\" role represents the model’s response to a user input. When we add {\"role\": \"assistant\", \"content\": assistant_msg} to the message history, we’re storing the model’s last reply. This helps maintain context in multi-turn conversations, allowing the model to remember what it said before and respond accordingly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ac664bef-21b0-4ffe-b427-82284ea751e0",
   "metadata": {},
   "outputs": [],
   "source": [
    "def example_4_conversation(messages):   \n",
    "    response = requests.post(\"http://localhost:11434/api/chat\", json={\n",
    "        \"model\": \"llama3.1:8b\",\n",
    "        \"messages\": messages,\n",
    "        \"stream\": False\n",
    "    })\n",
    "    \n",
    "    if response.status_code == 200:\n",
    "        assistant_msg = response.json()[\"message\"][\"content\"]\n",
    "        return assistant_msg"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43f73add-49da-4c21-b0fd-c6077cc2b11e",
   "metadata": {},
   "source": [
    "### Start conversation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b177fcb2-bb92-4634-9da1-ff968bc39b07",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"\\nExample 4: Conversation\")\n",
    "print(\"-\" * 30)\n",
    "messages = [{\"role\": \"system\", \"content\": \"You are a helpful coding assistant.\"}]\n",
    "messages.append({\"role\": \"user\", \"content\": \"How do I read a file in Python?\"})\n",
    "assistant_msg = example_4_conversation(messages)\n",
    "print(f\"Assistant:\\n{assistant_msg}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecf5c67c-e965-4ff6-9494-aa74952e67ae",
   "metadata": {},
   "source": [
    "### Add assistant:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ad8f2e8-40cd-4808-9535-4eac01c4ade6",
   "metadata": {},
   "outputs": [],
   "source": [
    "messages.append({\"role\": \"assistant\", \"content\": assistant_msg})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d21e9ae-56bf-476d-bc60-f438f089ad73",
   "metadata": {},
   "source": [
    "### Add follow-up question:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f404cd71-1b4f-4ce4-8fdd-4e770df77817",
   "metadata": {},
   "outputs": [],
   "source": [
    "messages.append({\"role\": \"user\", \"content\": \"What about error handling?\"})\n",
    "answer = example_4_conversation(messages)\n",
    "print(f\"\\n\\nFollow-up:\\n{answer}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "85bda394-a2b4-4e9e-a67b-18b0c30d8750",
   "metadata": {},
   "source": [
    "✅ All examples completed!\n",
    "\n",
    "💡 Key Points:\n",
    "\n",
    "• Replace OpenAI URLs with http://localhost:11434\n",
    "\n",
    "• No API keys needed!\n",
    "\n",
    "• ChatOllama replaces ChatOpenAI in LangChain"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
